package com.cn.transfer.controller;

import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.cn.transfer.common.constant.KeyConstant;
import com.cn.transfer.common.entity.ProductCodeApplication;
import com.cn.transfer.common.entity.ProductInfo;
import com.cn.transfer.common.entity.TokenMessage;
import com.cn.transfer.common.entity.jiandaoyun.JdyPurchaseOrder;
import com.cn.transfer.common.enumeration.MessageEnum;
import com.cn.transfer.common.http.ApiClient;
import com.cn.transfer.common.redis.RedisUtil;
import com.cn.transfer.common.utils.ConnmeUtils;
import com.cn.transfer.common.utils.MessageStrategyFactory;
import com.cn.transfer.common.utils.R;
import com.cn.transfer.common.vo.BizContentVO;
import com.cn.transfer.common.vo.EncryptedMessageVO;
import com.cn.transfer.common.vo.MessagePushVO;
import com.cn.transfer.handle.MessageStrategy;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * @author Administrator
 */
@RestController
@Slf4j
public class MessagePushContriller {

    @Autowired
    private RedisUtil redisUtil;
    private final MessageStrategyFactory messageStrategyFactory;

    @Autowired
    public MessagePushContriller(MessageStrategyFactory messageStrategyFactory) {
        this.messageStrategyFactory = messageStrategyFactory;
    }

    /**
     * 消息接收接口
     *
     * @param encryptedMessage
     * @return
     */
    @PostMapping("/verificationMessage")
    public Map<String, String> verificationMessage(@RequestBody EncryptedMessageVO encryptedMessage) {
        log.info(encryptedMessage.toString());
        byte[] key = KeyConstant.MESSAGE_KEY.getBytes(StandardCharsets.UTF_8);
        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
        byte[] decryptedData = aes.decrypt(encryptedMessage.getEncryptMsg());
        ObjectMapper objectMapper = new ObjectMapper();
        MessagePushVO decryptedMessage = null;
        try {
            decryptedMessage = objectMapper.readValue(decryptedData, MessagePushVO.class);
        } catch (IOException e) {
            throw new RuntimeException("/verificationMessage--63", e);
        }
        // 使用策略工厂创建对应的策略对象
        MessageStrategy strategy = messageStrategyFactory.createStrategy(decryptedMessage.getMsgType());
        if (strategy != null) {
            MessagePushVO finalDecryptedMessage = decryptedMessage;
            CompletableFuture.runAsync(() -> {
                try {
                    strategy.handle(finalDecryptedMessage);
                } catch (Exception e) {
                    log.error("异步消息处理期间出错:====>", e);
                }
            });
        }
        log.info(decryptedMessage.toString());
        log.info(String.valueOf(decryptedMessage.getBizContent()));
        Map<String, String> map = new HashMap<String, String>();
        map.put("result", "success");
        return map;
    }


    /**
     * 自建应用获取token
     */
    @PostMapping("/getToken")
    public R getToken() {
        Map<String, Object> parameter = new HashMap<>();
        //接口开放平台的appTicket消息获得，请去管理后台配置消息地址
        ObjectMapper objectMapper = new ObjectMapper();
        BizContentVO bean = null;
        try {
            bean = objectMapper.readValue(JSONUtil.toJsonStr(redisUtil.get(MessageEnum.APP_TICKET.getChinese())), BizContentVO.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        parameter.put("appTicket", bean.getAppTicket());
        // 加密证书，自建应用通过管理员授权后获得
        parameter.put("certificate", KeyConstant.CERTIFICATE);
        String jsonStr = JSONUtil.toJsonStr(parameter);
        String reult = HttpRequest.post(KeyConstant.T_URL + "/v1/common/auth/selfBuiltApp/generateToken").header("appKey", KeyConstant.APPKEY)
                .header("appSecret", KeyConstant.APPSECRET)
                .header("Content-Type", "application/json")
                .body(jsonStr)
                .execute().body();
        JSONObject jsonObject = JSONUtil.parseObj(reult);
        if (jsonObject.getStr("error") != null) {
            log.error("getToken: " + jsonObject.getStr("error"));
        }
        TokenMessage value = JSONUtil.toBean(jsonObject.getStr("value"), TokenMessage.class);
        redisUtil.set("token_info", jsonObject.getStr("value"), -1);
        return R.ok(value);
    }

    /**
     * T+消息订阅验证消息
     */
    @GetMapping("/newsSubscription")
    public Map<String, String> newsSubscription(@RequestParam String echostr,
                                                @RequestParam String nonce,
                                                @RequestParam String signature,
                                                @RequestParam String timestamp) {
        // 将 token、timestamp、nonce 三个参数进行字典序排序
        log.info(echostr + "\n" + nonce + "\n" + signature + "\n" + timestamp);
        final String TOKEN = "ljyyzsfwfwfw";
        String[] arr = new String[]{TOKEN, timestamp, nonce};
        Arrays.sort(arr);

        // 将排序后的参数拼接成一个字符串
        StringBuilder sb = new StringBuilder();
        for (String s : arr) {
            sb.append(s);
        }

        // 使用 SHA1 对字符串进行加密
        String encryptedStr = sha1(sb.toString());

        log.info(signature + " 0 " + encryptedStr);
        // 验证签名是否正确
        Map<String, String> result = new HashMap<>();
        if (encryptedStr.trim().equalsIgnoreCase(signature.trim())) {
            // 验证通过，返回 echostr 给 T+ 平台
            result.put("echostr", echostr);
        } else {
            // 验证失败，返回错误信息
            result.put("error", "Signature mismatch");
        }
        return result;
    }


    // SHA1 加密方法
    private String sha1(String input) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            byte[] bytes = digest.digest(input.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return "";
        }
    }

    private static final String SECRET = "KPIfb04KeXBOWkj3m9xDqKV9";
    private static final String DATA_CREATE = "data_create";
    private static final String DATA_UPDATE = "data_update";
    private static final String DATA_DELETE = "data_remove";

    @PostMapping("/callback")
    public String callback(@RequestParam("nonce") String nonce,
                           @RequestParam("timestamp") String timestamp,
                           @RequestHeader("x-jdy-signature") String signature,
                           @RequestBody String payload) {
        //log.info("存货申请=====" + payload);
        if (!validateSignature(nonce, payload, timestamp, signature)) {
            return "fail";
        }
        // 在这里处理消息
        handleData(payload);

        return "success";
    }

    private boolean validateSignature(String nonce, String payload, String timestamp, String signature) {
        String calculatedSignature = getSignature(nonce, payload, MessagePushContriller.SECRET, timestamp);
        return calculatedSignature.equals(signature);
    }

    private String getSignature(String nonce, String payload, String secret, String timestamp) {
        return DigestUtils.sha1Hex(nonce + ":" + payload + ":" + secret + ":" + timestamp);
    }

    private void handleData(String payload) {
        // 在这里处理推送来的数据
        JSONObject payloadJSON = JSONUtil.parseObj(payload);
        String op = payloadJSON.getStr("op");
        String data = payloadJSON.getStr("data");

        if (DATA_UPDATE.equals(op)) {
            update(data);
        }
    }


    private void update(String data) {
        // 处理更新数据的逻辑
        ProductCodeApplication productCodeApplication = JSONUtil.toBean(data, ProductCodeApplication.class);
        Header[] headers = ConnmeUtils.createHeaders();
        Map<String, Object> parameterDelete = new HashMap<>();
        parameterDelete.put("instance_id", productCodeApplication.get_id());
        parameterDelete.put("tasks_type", 1);
        String jsonSale = JSONUtil.toJsonStr(parameterDelete);
        JSONObject jdySale = ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v4/workflow/instance/get", headers, jsonSale);
        JdyPurchaseOrder jdyPurchaseOrder = JSONUtil.toBean(jdySale, JdyPurchaseOrder.class);
        Header[] headerse = new Header[4];
        headerse[0] = new BasicHeader("appKey", KeyConstant.APPKEY);
        headerse[1] = new BasicHeader("Content-Type", "application/json");
        headerse[2] = new BasicHeader("appSecret", KeyConstant.APPSECRET);
        headerse[3] = new BasicHeader("openToken", redisUtil.get("token_info").toString());

        log.info(jdyPurchaseOrder.toString());
        if (productCodeApplication.getApplication_content().equals("TB02")) {
            int size = jdyPurchaseOrder.getTasks().size() - 1;
            String flow_name = jdyPurchaseOrder.getTasks().get(size).getFlow_name();
            if (jdyPurchaseOrder.getStatus() == 0 && flow_name.equals("申请人确认编码")) {
                String entries = toJson(productCodeApplication, false, false, false, false,0);
                JSONObject entries1 = ApiClient.sendPostRequest(KeyConstant.T_URL + "/tplus/api/v2/inventory/Create", headerse, entries);
                log.info("TB02存货申请申请人确认编码新增===" + productCodeApplication);
                log.info("TB02存货申请申请人确认编码新增===" + entries1);
            } else if (jdyPurchaseOrder.getStatus() == 1) {
                String entries = toJson(productCodeApplication, true, true, true, true,0);
                JSONObject entries1 = ApiClient.sendPostRequest(KeyConstant.T_URL + "/tplus/api/v2/inventory/Update", headerse, entries);
                log.info("TB02存货申请流程完成更新===" + productCodeApplication);
                log.info("TB02存货申请流程完成更新===" + entries1);
            } else if (jdyPurchaseOrder.getStatus() == 2) {
                ProductInfo productInfo = new ProductInfo();
                productInfo.setCode(productCodeApplication.getInventory_code());
                // 存货名称
                String cuns = "(停用)" + productCodeApplication.getCategory() + "." + productCodeApplication.getModel() + " " + productCodeApplication.getProduct_name();
                productInfo.setName(cuns);
                productInfo.setSpecification(productCodeApplication.getSpecification_model());

                ProductInfo.ValueType valueType = new ProductInfo.ValueType();
                valueType.setCode("03");
                productInfo.setValueType(valueType);

                ProductInfo.InventoryClass inventoryClass = new ProductInfo.InventoryClass();
                inventoryClass.setCode(productCodeApplication.getCategory());
                productInfo.setInventoryClass(inventoryClass);

                ProductInfo.Unit unit = new ProductInfo.Unit();
                unit.setName(productCodeApplication.getPrimary_measurement());
                productInfo.setUnit(unit);

                productInfo.setPurchase(false);
                productInfo.setSale(false);
                productInfo.setMadeSelf(true);
                productInfo.setMaterial(false);
                productInfo.setMadeRequest(false);
                productInfo.setSerialNumber(false);
                productInfo.setBatch(false);
                productInfo.setInventoryDescript(productCodeApplication.getPacking_method());
                List<String> dynamicPropertyValues1 = new ArrayList<>();
                List<String> dynamicPropertyKeys1 = new ArrayList<>();
                dynamicPropertyKeys1.add("priuserdefnvc6");
                dynamicPropertyValues1.add(cuns);
                productInfo.setDynamicPropertyKeys(dynamicPropertyKeys1);
                productInfo.setDynamicPropertyValues(dynamicPropertyValues1);
                Map<String, Object >  dynamicProperty=new HashMap<>();
                dynamicProperty.put("dto",productInfo);
                String entries = JSONUtil.toJsonStr(dynamicProperty);
                JSONObject entries1 = ApiClient.sendPostRequest(KeyConstant.T_URL + "/tplus/api/v2/inventory/Update", headerse, entries);
                log.info("TB02存货停用申请===" + productCodeApplication);
                log.info("TB02存货停用申请===" + entries1);
            }
        } else if (productCodeApplication.getApplication_content().equals("TB03")) {
            if (jdyPurchaseOrder.getStatus() == 1) {
                String entries = toJson(productCodeApplication, true, true, true, true,1);
                JSONObject entries1 = ApiClient.sendPostRequest(KeyConstant.T_URL + "/tplus/api/v2/inventory/Update", headerse, entries);
                log.info("TB03存货申请更新===" + productCodeApplication);
                log.info("TB03存货申请更新===" + entries1);
            }
        }
    }


    private String toJson(ProductCodeApplication productCodeApplication, Boolean i1, Boolean i2, Boolean i4, Boolean i5,int i6) {
        ProductInfo productInfo = new ProductInfo();
        if (i6==0){
            productInfo.setCode(productCodeApplication.getInventory_code());
        }else {
            productInfo.setCode(productCodeApplication.getOriginal_inventory_code());
        }
        // 存货名称
        String cuns = productCodeApplication.getCategory() + "." + productCodeApplication.getModel() + " " + productCodeApplication.getProduct_name();
        productInfo.setName(cuns);
        productInfo.setSpecification(productCodeApplication.getSpecification_model());

        ProductInfo.ValueType valueType = new ProductInfo.ValueType();
        valueType.setCode("03");
        productInfo.setValueType(valueType);

        ProductInfo.InventoryClass inventoryClass = new ProductInfo.InventoryClass();
        inventoryClass.setCode(productCodeApplication.getCategory());
        productInfo.setInventoryClass(inventoryClass);

        ProductInfo.Unit unit = new ProductInfo.Unit();
        unit.setName(productCodeApplication.getPrimary_measurement());
        productInfo.setUnit(unit);

        productInfo.setPurchase(i1);
        productInfo.setSale(i2);
        productInfo.setMadeSelf(true);
        productInfo.setMaterial(i4);
        productInfo.setMadeRequest(i5);
        productInfo.setInventoryDescript(productCodeApplication.getPacking_method());
        List<String> dynamicPropertyValues1 = new ArrayList<>();
        dynamicPropertyValues1.add(productCodeApplication.getBcxx());
        dynamicPropertyValues1.add(productCodeApplication.getPacking_method());
        dynamicPropertyValues1.add(cuns);
        dynamicPropertyValues1.add(productCodeApplication.getSpecification_model());
        dynamicPropertyValues1.add(productCodeApplication.getBcxx());
        dynamicPropertyValues1.add("暂无");
        if (productCodeApplication.getProcurement_responsible().getName().equals("张欣欣")){
            dynamicPropertyValues1.add(".");
        }else {
            dynamicPropertyValues1.add(productCodeApplication.getProcurement_responsible().getName());
        }

        dynamicPropertyValues1.add(productCodeApplication.getOrigin());
        dynamicPropertyValues1.add(productCodeApplication.getPacking_specification());
        List<String> dynamicPropertyKeys1 = new ArrayList<>();
        dynamicPropertyKeys1.add("priuserdefnvc1");
        dynamicPropertyKeys1.add("priuserdefnvc4");
        dynamicPropertyKeys1.add("priuserdefnvc6");
        dynamicPropertyKeys1.add("priuserdefnvc7");
        dynamicPropertyKeys1.add("priuserdefnvc3");
        dynamicPropertyKeys1.add("priuserdefnvc5");
        dynamicPropertyKeys1.add("priuserdefnvc9");
        dynamicPropertyKeys1.add("priuserdefnvc8");
        dynamicPropertyKeys1.add("priuserdefnvc2");
        productInfo.setDynamicPropertyKeys(dynamicPropertyKeys1);
        productInfo.setDynamicPropertyValues(dynamicPropertyValues1);

        Map<String, Object >  dynamicProperty=new HashMap<>();
        dynamicProperty.put("dto",productInfo);
        return JSONUtil.toJsonStr(dynamicProperty);
    }

}
